import React, { useRef, useState, useEffect } from 'react';
import { Toast, Modal } from 'antd-mobile';
import { Progress } from 'antd';
import classnames from 'classnames';
import Icon from '../Icon';
import {
  validFiles,
  uid,
  getBase64,
  replaceFile,
  getFile,
  removeFile,
  upload as request,
} from './util';
import './index.less';
import moment from 'moment'

type File = {
  uid: number | string;
  name: string;
  status: 'uploading' | 'done' | 'error';
  url: string;
  message?: string;
  /**
   * 额外的数据
   */
  payload?: any;
};

type ExtraFile = File & {
  file?: any;
  percent?: number;
};

export interface UploadProps {
  type: 'idcard-front' | 'idcard-backend' | 'card' | 'icon-card'| 'icon-btn';
  sourceType?: ('album' | 'camera')[]; // 相册 or 相机
  max?: number;
  multiple?: boolean;
  /**
   * 字段
   */
  sizeLimit?: number;
  beforeUpload?: (files) => boolean;
  fileList?: File[];
  headers?: any;
  /**
   * 上传图片的服务器地址
   */
  url: string;
  data?: any;
  filename?: string;
  disabled?: boolean;
  canDelete?: boolean;
  formItemName?: string;
  /**
   * 请求响应的回调，
   * 这里可以根据后台接口响应处理文件的状态 "done" 或者 "error"
   */
  onRespone?: ((data, file: File) => Promise<File>) | ((data, file: File) => File);
  onSuccess?: (file: File, files: File[]) => void;
  onFinsh?: (files: File[]) => void;
  onRemove?: (file: File, files: File[]) => void;
  beforeRemove?: (file) => Promise<boolean>;
  onChange?: (fileList: File[]) => void;
  RenderIcon?: (data) => JSX.Element;
  icon?:JSX.Element;
}

const Upload: React.FunctionComponent<UploadProps> = (props) => {
  const {
    type,
    sourceType,
    multiple,
    sizeLimit,
    beforeUpload,
    data,
    url,
    headers,
    filename,
    onSuccess,
    onFinsh,
    disabled,
    canDelete,
    onChange,
    fileList: propsFileList,
    RenderIcon,
    onRemove,
    beforeRemove,
    onRespone,
    max,
    formItemName,
    icon,
    ...otherProps
  } = props;
  const inputRef = useRef(null);
  const currentClickFile = useRef(null);
  const uploadTask = useRef({});
  const [fileList, setFileList] = useState(propsFileList || []);
  const fileListTotal = useRef(propsFileList || []);
  const [showActionSheet, setShowActionSheet] = useState(false);
  const [showPriviewImage, setShowPriviewImage] = useState(false);
  useEffect(() => {
    if (propsFileList === undefined) return;
    setFileList(propsFileList);
    fileListTotal.current = propsFileList;
  }, [propsFileList]);

  /**
   * change 回调
   * @param files
   */
  const handleChange = (files) => {
    if (typeof onChange === 'function') {
      onChange(files);
    }
  };

  /**
   * 进度条
   * @param e
   * @param file
   */
  const onProgress = (e, file) => {
    const newFile = getFile(file, fileListTotal.current);
    const percent = e && e.percent ? e.percent : 0;
    newFile.percent = Math.min(99, Math.round(percent));
    const newFiles = replaceFile(newFile, file, fileListTotal.current);
    fileListTotal.current = newFiles;
    setFileList(newFiles);
    // handleChange(newFiles);
  };

  /**
   * 文件上传成功回调
   * @param ret
   * @param file
   * @param xhr
   */
  const handleSuccess = async (ret, file, xhr) => {
    const response = JSON.parse(xhr.response);
    let newFile = getFile(file, fileListTotal.current);

    /**
     * 格式化下url
     */
    if (typeof onRespone === 'function') {
      newFile = await onRespone(response, newFile);
    }

    if (newFile.status !== 'error') {
      newFile.status = 'done';
    }

    const newFiles = replaceFile(newFile, file, fileListTotal.current);

    fileListTotal.current = newFiles;
    setFileList(newFiles);
    handleChange(newFiles);
    if (typeof onSuccess === 'function') {
      onSuccess(newFile, newFiles);
    }

    // 删除任务
    delete uploadTask.current[newFile.uid];
    // 当任务全部完成触发onFinsh
    if (Object.keys(uploadTask.current).length <= 0 && typeof onFinsh === 'function') {
      onFinsh(fileListTotal.current);
    }
  };

  /**
   * 文件上传失败回调
   * @param err
   * @param ret
   * @param file
   */
  const onError = (err, ret, file) => {
    const newFile = getFile(file, fileListTotal.current);
    console.group('onError');
    console.log(err);
    console.log(ret);
    console.groupEnd();
    newFile.status = 'error';
    newFile.message = ret && ret.message ? ret.message : '上传失败';
    const newFiles = replaceFile(newFile, file, fileListTotal.current);
    fileListTotal.current = newFiles;
    setFileList(newFiles);
    handleChange(newFiles);

    // 删除任务
    delete uploadTask.current[newFile.uid];
    // 当任务全部完成触发onFinsh
    if (Object.keys(uploadTask.current).length <= 0 && typeof onFinsh === 'function') {
      onFinsh(fileListTotal.current);
    }
  };

  /**
   * 开始上传任务
   */
  const startUploadTask = () => {
    fileList.map(async (item: ExtraFile) => {
      if (uploadTask.current[item.uid] || item.status !== 'uploading') return;
      const requestOption = {
        url,
        filename,
        data,
        file: item.file,
        headers,
        method: 'post',
        onProgress: (e) => onProgress(e, item),
        onSuccess: (ret, xhr) => {
          handleSuccess(ret, item, xhr);
        },
        onError: (err, ret) => {
          onError(err, ret, item);
          delete uploadTask.current[item.uid];
        },
      };
      const xhr = request(requestOption);
      uploadTask.current[item.uid] = xhr;
    });
  };

  /**
   * 文件更新后开始上传的回调Effect
   */
  useEffect(() => {
    startUploadTask();
    // const timer = setTimeout(startUploadTask, 0);
    // return () => {
    //   // clearTimeout(timer);
    // };
  }, [fileList]);

  const upload = async (files) => {
    const filesPromise = [...files].map(async (item) => {
      const fileUrl = await getBase64(item);
      return {
        name: item.name,
        uid: uid(),
        status: 'uploading',
        url: fileUrl,
        percent: 1,
        file: item,
      };
    }) as Promise<File>[];

    const filesResult = await Promise.all(filesPromise);

    let newFiles = [...fileListTotal.current, ...filesResult];
    /**
     * 存在currentClickFile，说明是重新上传, 替换原有的
     */
    if (currentClickFile.current) {
      newFiles = replaceFile(filesResult[0], currentClickFile.current, fileListTotal.current);
    }
    fileListTotal.current = newFiles;
    setFileList(newFiles);
  };

  /**
   *
   * file input change的监听
   */
  const inputHandleChange = async (e) => {
    setShowActionSheet(false);
    const files = Array.from(e.target.files);
    if (typeof beforeUpload === 'function' && (await beforeUpload(files)) === false) {
      e.target.value = '';
      return;
    }
    const validResult = validFiles(files, { sizeLimit });
    if (validResult.status !== 0) {
      Toast.fail(validResult.message);
    }
    console.log(props)
    if ((files.length + fileList.length) > max) {
      Toast.fail(`上传数量超过材料限定数量${max}张`);
      e.target.value = '';
      return;
    }
    // 开始上传
    upload(files);
    e.target.value = '';
  };

  /**
   * input file 组件
   * @param className
   */
  const inputCapture = (className = {}) => {
    const inputProps = {
      ref: inputRef,
      className: classnames('hr-input', className),
      type: 'file',
      accept: 'image/*',
      multiple,
      onChange: inputHandleChange,
      disabled,
    } as any;
    const ua = navigator.userAgent.toLowerCase();

    /**
     * 直接拉起相机
     */
    if (sourceType.length === 1 && sourceType[0] === 'camera') {
      inputProps.capture = 'environment';
      inputProps.multiple = false;
    }

    /**
     * 小程序webview，安卓需要加上capture= environment，
     * 才能有相机和相册2个选项
     */
    if (ua.includes('miniprogram') && sourceType.length === 2 && /android/i.test(ua)) {
      inputProps.capture = 'environment';
    }

    return (
      <input
        {...inputProps}
        style={{
          opacity: 0,
          position: 'absolute',
          width: '100%',
          height: '100%',
          left: 0,
          top: 0,
        }}
      />
    );
  };

  const hanleImageClick = (item: File) => {
    if (disabled || (canDelete === false)) {
      currentClickFile.current = item;
      setShowPriviewImage(true);
      return;
    }
    if (!item || item.status === 'uploading') return;
    currentClickFile.current = item;
    setShowActionSheet(true);
  };

  const handlePriviewImage = () => {
    setShowActionSheet(false);
    setShowPriviewImage(true);
  };

  const handleRemove = async () => {
    if (currentClickFile.current) {
      if (typeof beforeRemove === 'function') {
        const flag = await beforeRemove({...currentClickFile.current, formItemName});
        // currentClickFile.current = null;
        if (!flag) return;
      }
      // 取消上传
      const task = uploadTask.current[currentClickFile.current.uid];
      if (task && typeof task.abort === 'function') {
        // 删除任务
        task.abort();
        delete uploadTask.current[currentClickFile.current.uid];
      }

      const newFiles = removeFile(currentClickFile.current, fileList);
      setFileList(newFiles);
      handleChange(newFiles);
      fileListTotal.current = newFiles;
      if (typeof onRemove === 'function') {
        onRemove(currentClickFile.current, newFiles);
      }

      // 当任务全部完成触发onFinsh
      if (Object.keys(uploadTask.current).length <= 0 && typeof onFinsh === 'function') {
        onFinsh(fileListTotal.current);
      }

      // 清空当前的文件指向
      currentClickFile.current = null;
    }
    setShowActionSheet(false);
  };

  const handleRemoveIconClick = (item: File, e) => {
    e.stopPropagation();
    currentClickFile.current = item;
    handleRemove();
  };

  const handleClose = () => {
    currentClickFile.current = null;
    setShowActionSheet(false);
  };
  const renderUpload = () => {
    /**
     * 身份证正反面
     */
    if (type === 'idcard-front' || type === 'idcard-backend') {
      const file = fileList[0] as ExtraFile;
      return (
        <div className={classnames('hr-idcard', type)} onClick={() => hanleImageClick(file)}>
          <i className="idcard-icon" />
          {fileList && fileList.length > 0 ? (
            <>
              <i className="hr-upload-img" style={{ backgroundImage: `url(${file.url})` }} />
              {file.status === 'uploading' && (
                <Progress percent={file.percent} status="active" className="hr-upload-progress" />
              )}
              {file.status === 'error' && (
                <span className={classnames('hr-upload-message', file.status)}>{file.message}</span>
              )}
            </>
          ) : (
            inputCapture()
          )}
        </div>
      );
    }
    /**
     * @description: 上传按钮在已上传图片后面
     */  
    if (type === 'card') {
      return (
        <div className={classnames('hr-card', type)}>
          {fileList.map((item: ExtraFile) => {
            return (
              <div className="hr-card-item" key={item.uid} onClick={() => hanleImageClick(item)}>
                <i className="hr-upload-img" style={{ backgroundImage: `url(${item.url})` }} />
                {item.status === 'uploading' && (
                  <Progress percent={item.percent} status="active" className="hr-upload-progress" />
                )}
                {item.status === 'error' && (
                  <span className={classnames('hr-upload-message', item.status)}>
                    {item.message || ''}
                  </span>
                )}
                {item.status === 'done' && typeof RenderIcon === 'function' && RenderIcon(item)}
                {(!disabled && (canDelete !== false))&& (
                  <Icon
                    type="cross-circle"
                    className="hr-upload-remove-icon"
                    onClick={(e) => handleRemoveIconClick(item, e)}
                  />
                )}
              </div>
            );
          })}
          {(!fileList || fileList.length) < max && !disabled && (
            <div className="hr-card-item">
              <i className="idcard-icon" />
              {inputCapture()}
            </div>
          )}
        </div>
      );
    }
    /**
     * @description: 上传按钮在图片标题后面
     */  
    if (type === 'icon-card') {
      return (
        <div className={classnames('hr-card', type)}>
          {(!fileList || fileList.length) < max && !disabled && (
            <div className="hr-card-icon">
              {icon?icon:<i className="idcard-icon" />}
              {inputCapture()}
            </div>
          )}
          {fileList.map((item: ExtraFile) => {
            return (
              <div className="hr-card-item" key={item.uid} onClick={() => hanleImageClick(item)}>
                <i className="hr-upload-img" style={{ backgroundImage: `url(${item.url})` }} />
                {item.status === 'uploading' && (
                  <Progress percent={item.percent} status="active" className="hr-upload-progress" />
                )}
                {item.status === 'error' && (
                  <span className={classnames('hr-upload-message', item.status)}>
                    {item.message || ''}
                  </span>
                )}
                {item.status === 'done' && typeof RenderIcon === 'function' && RenderIcon(item)}
                {(!disabled && (canDelete !== false)) && (
                  <Icon
                    type="cross-circle"
                    className="hr-upload-remove-icon"
                    onClick={(e) => handleRemoveIconClick(item, e)}
                  />
                )}
              </div>
            );
          })}
        </div>
      );
    }
    if (type === 'icon-btn'){
      return (
        <div  className={classnames('hr-card-icon', type)}>
        {icon?icon:<Icon type="iconxiangji"/>}
        {inputCapture()}
      </div>
      );
    }
  };

  // 关闭图片查看器
  const closePriviewImage = () => {
    setShowPriviewImage(false)
    currentClickFile.current = null;
  }
  return (
    <div className={`hr-upload ${fileList.length === 0 ? '' : 'am-accordion-content-box-padding'}`} {...otherProps}>
      {renderUpload()}

      <Modal
        className="hr-actionsheet-modal"
        visible={showActionSheet}
        transparent
        maskClosable
        popup
        onClose={handleClose}
        animationType="slide-up"
      >
        <div className="hr-actionsheet">
          <div className="hr-actionsheet-item" onClick={handlePriviewImage}>
            查看
          </div>
          {
            type === 'icon-card' ? '' : <div className="hr-actionsheet-item">重新上传{inputCapture()}</div>
          }
          <div className="hr-actionsheet-item delete" onClick={handleRemove}>
            删除
          </div>
          <div className="hr-actionsheet-item" onClick={handleClose}>
            取消
          </div>
        </div>
      </Modal>
      <Modal
        className="hr-priview-img"
        visible={showPriviewImage}
        transparent
        maskClosable
        onClose={closePriviewImage}
      >
        <div className="hr-priview-wrapper">
          <div className="hr-priview-img-info">
            <p>{currentClickFile.current?.imageAddr}</p>
            <p>{currentClickFile.current?.createDate ? moment(currentClickFile.current?.createDate).format('YYYY-MM-DD h:mm:ss') : ''}</p>
          </div>
          <i
            className="img"
            style={{
              backgroundImage: `url(${
                currentClickFile.current &&
                (currentClickFile.current.originUrl || currentClickFile.current.url)
              })`,
            }}
            onClick={closePriviewImage}
          />
        </div>
      </Modal>
    </div>
  );
};
Upload.defaultProps = {
  sourceType: ['album', 'camera'],
  max: 9999,
  multiple: true,
  filename: 'file',
};
export default Upload;
